/*
 * =====================================================================================
 *
 *       Filename:  compiler.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  02/28/12 14:43:06
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  randyli (randy), randyli@tencent.com
 *        Company:  Tencent
 *
 * =====================================================================================
 */
#include <string.h>
#include <memory.h>
#include <stdlib.h>
#include "compiler.h"

int add_iopcode(scompiler* compiler, int opcode, int   arg1)
{
	compiler->ops[compiler->ops_num].op = opcode;
	ivalue(compiler->ops[compiler->ops_num].arg1) = arg1;
	compiler->ops_num++;
	return 0;
}

int add_tmp_iopcode(scompiler* compiler, int opcode, int   arg1)
{
	compiler->tmp_ops[compiler->tmp_ops_num].op = opcode;
	ivalue(compiler->tmp_ops[compiler->tmp_ops_num].arg1) = arg1;
	compiler->tmp_ops_num++;
	return 0;
}

int merge_opcode(scompiler* compiler)
{
	memcpy(&(compiler->ops[compiler->ops_num]), compiler->tmp_ops, sizeof(opcode)*compiler->tmp_ops_num);
	compiler->ops_num += 	compiler->tmp_ops_num;
	compiler->tmp_ops_num = 0;
	return 0;
}

int set_iopcode(scompiler* compiler, int pos, int opcode, int   arg1)
{
	compiler->ops[pos].op = opcode;
	ivalue(compiler->ops[pos].arg1) = arg1;
	return 0;
}


int add_fopcode(scompiler* compiler, int opcode, float arg1)
{
	
	compiler->ops[compiler->ops_num].op = opcode;
	fvalue(compiler->ops[compiler->ops_num].arg1) = arg1;
	compiler->ops_num++;
	return 0;
}
int add_sopcode(scompiler* compiler, int opcode, char* arg1)
{
	compiler->ops[compiler->ops_num].op = opcode;
	svalue(compiler->ops[compiler->ops_num].arg1) = arg1;
	compiler->ops_num++;
	return 0;
}

int append_sconst(scompiler* compiler, const char* str)
{
	int tmp = compiler->sconst_pos;
	strcpy(compiler->sconst + compiler->sconst_pos, str);
	compiler->sconst_pos += strlen(str) + 1;
	return tmp;
}

// open tag stack opration
int open_tag(scompiler* compiler, const char* type, int arg1, int arg2)
{
	tag* t =&( compiler->open_tags[compiler->open_tag_num++] );
	strcpy(t->type, type);
	t->arg1 = arg1;
	t->arg2 = arg2;
	return 0;
}
tag* top_tag(scompiler* compiler)
{
	if(compiler->open_tag_num <=0 )	 return NULL;
	tag* t =&( compiler->open_tags[compiler->open_tag_num - 1] );
	return t;
}
int close_tag(scompiler* compiler, const char* type)
{
	if(compiler->open_tag_num <=0 )	 return -1;
	tag* t =&( compiler->open_tags[compiler->open_tag_num - 1] );
	if(strcmp(t->type, type) != 0 ) return -1;
	compiler->open_tag_num--;
	return 0; 
}

// variable 
int tmp_variable(scompiler* compiler, const char* name)
{
	smt_array* st = compiler->st;
	int s_offset = get_symbol(st, name);
	if(s_offset < 0)
	{
		append_sconst(compiler, name);
		s_offset = st->length;
		add_symbol(st, name, s_offset);
	}
	return s_offset;
}


int rand_variable(scompiler* compiler, const char* prefix, char* out)
{
	sprintf(out, "%s_%d", prefix, compiler->rand_index++);
	return 0;
}

int add_symbol(smt_array* st, const char* name, int name_offset)
{
	symbol* s = (symbol*)malloc(sizeof(symbol));
	strcpy(s->name, name);
	//printf("add %s\n", s->name);
	s->offset = name_offset;
	smt_array_set(st, name, strlen(name), s);
	return s->offset;
}

int get_symbol(smt_array* st, const char* name)
{
	symbol*s = smt_array_assoc_get(st, name, strlen(name));
	if(s)
	{
		return s->offset;
	}
	return -1;
}

int compiler_init(scompiler** p_compiler)
{
	scompiler* c = (scompiler*)malloc(sizeof(scompiler));
	c->lex = (lexer*)malloc(sizeof(lexer));
	c->parser = ParseAlloc (malloc);
	smt_array_new(&(c->st));
	add_symbol(c->st, "$smarty", 0);	
	add_symbol(c->st, "$data", 1);	
	c->open_tag_num = 0;
	
	*p_compiler = c;
	c->sconst_pos = 0;
	c->ops_num = 0;	
	c->tmp_ops_num = 0;
	c->rand_index = 0;

	return 0;
}

int compile_str(scompiler* compiler, char* str, int len)
{
	lexer* l = compiler->lex;
	l->buf = str;
	l->len = len;
	l->cursor = str;
	l->yystate = STATE(INITIAL);
#ifdef __DEBUG
	compiler->dfp = fopen("parser.debug", "w+");
#endif 
	
	memset(compiler->ops, 0, sizeof(compiler->ops));
	compiler->ops_num = 0;
	token t;
	while(get_next_token(l, &t))
	{
		//printf("%d \n", t.type);
		Parse(compiler->parser, t.type , t, compiler);
#ifdef __DEBUG
	ParseTrace(compiler->dfp, "");
#endif
	}
	Parse (compiler->parser, 0, t, compiler);
	
	return 0;
}
int compiler_destroy(scompiler* compiler)
{
	return 0;
}
